<HTML
><HEAD
><TITLE
>HOWTO: Programming S/MIME in Python with M2Crypto</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.64
"></HEAD
><BODY
CLASS="ARTICLE"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="ARTICLE"
><DIV
CLASS="TITLEPAGE"
><H1
CLASS="TITLE"
><A
NAME="AEN2"
>HOWTO: Programming S/MIME in Python with M2Crypto</A
></H1
><H3
CLASS="AUTHOR"
><A
NAME="AEN4"
>Pheng Siong Ng</A
></H3
><DIV
CLASS="AFFILIATION"
><DIV
CLASS="ADDRESS"
><P
CLASS="ADDRESS"
>ngps@post1.com</P
></DIV
></DIV
><P
CLASS="COPYRIGHT"
>Copyright &copy; 2000, 2001 by Ng Pheng Siong.</P
><DIV
CLASS="REVHISTORY"
><TABLE
WIDTH="100%"
BORDER="0"
><TR
><TH
ALIGN="LEFT"
VALIGN="TOP"
COLSPAN="3"
><B
>Revision History</B
></TH
></TR
><TR
><TD
ALIGN="LEFT"
>Revision $Id: howto.smime.html 646 2008-10-29 03:12:56Z heikki $</TD
><TD
ALIGN="LEFT"
></TD
><TD
ALIGN="LEFT"
></TD
></TR
><TR
><TD
ALIGN="LEFT"
COLSPAN="3"
></TD
></TR
></TABLE
></DIV
><HR></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="INTRODUCTION"
>Introduction</A
></H1
><P
><A
HREF="http://chandlerproject.org/Projects/MeTooCrypto"
TARGET="_top"
>M2Crypto</A
> 
    is a <A
HREF="http://www.python.org"
TARGET="_top"
>Python</A
>
    interface to <A
HREF="http://www.openssl.org"
TARGET="_top"
>OpenSSL</A
>. It makes 
    available to the Python programmer SSL functionality to implement clients 
    and servers, S/MIME v2, RSA, DSA, DH, symmetric ciphers, message digests and 
    HMACs.
    </P
><P
>This document demonstrates programming S/MIME with M2Crypto.
    </P
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="SMIME"
>S/MIME</A
></H1
><P
>S/MIME - Secure Multipurpose Internet Mail Extensions
    [<SPAN
CLASS="CITATION"
>RFC 2311, RFC 2312</SPAN
>] - provides a 
    consistent way to send and receive secure MIME data.  Based on the popular 
    Internet MIME standard, S/MIME provides the following cryptographic security 
    services for electronic messaging applications - 
    <I
CLASS="EMPHASIS"
>authentication</I
>, <I
CLASS="EMPHASIS"
>message integrity </I
> 
    and <I
CLASS="EMPHASIS"
>non-repudiation of origin </I
> (using <I
CLASS="EMPHASIS"
>digital 
    signatures</I
>), and <I
CLASS="EMPHASIS"
>privacy </I
> and <I
CLASS="EMPHASIS"
>data 
    security</I
> (using <I
CLASS="EMPHASIS"
>encryption</I
>).  
    </P
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="KEYS-AND-CERTIFICATES"
>Keys and Certificates</A
></H1
><P
>To create an S/MIME-signed message, you need an RSA key pair
    (this consists of a public key and a private key) and an X.509
    certificate of said public key.
    </P
><P
>To create an S/MIME-encrypted message, you need an X.509
    certificate for each recipient.
    </P
><P
>To create an S/MIME-signed <I
CLASS="EMPHASIS"
>and</I
> -encrypted 
    message, first create a signed message, then encrypt the signed
    message with the recipients' certificates.
    </P
><P
>You may generate key pairs and obtain certificates by using a
    commercial <I
CLASS="EMPHASIS"
>certification authority</I
> service.
    </P
><P
>You can also do so using freely-available software. For many 
    purposes, e.g., automated S/MIME messaging by system administration 
    processes, this approach is cheap and effective.
    </P
><P
>We now work through using OpenSSL to generate key pairs and
    certificates. This assumes you have OpenSSL installed properly on your
    system.
    </P
><P
>First, we generate an X.509 certificate to be used for signing:
    </P
><PRE
CLASS="SCREEN"
>    <TT
CLASS="USERINPUT"
><B
>openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out signer.pem
    </B
></TT
>
    Using configuration from /usr/local/pkg/openssl/openssl.cnf
    Generating a 1024 bit RSA private key
    ..++++++
    ....................++++++
    writing new private key to 'privkey.pem'
    -----
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [AU]:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>SG</I
></TT
></B
></TT
>
    State or Province Name (full name) [Some-State]:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>.</I
></TT
></B
></TT
>
    Locality Name (eg, city) []:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>.</I
></TT
></B
></TT
>
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>M2Crypto</I
></TT
></B
></TT
>
    Organizational Unit Name (eg, section) []:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>.</I
></TT
></B
></TT
>
    Common Name (eg, YOUR name) []:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>S/MIME Sender</I
></TT
></B
></TT
>
    Email Address []:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>sender@example.dom</I
></TT
></B
></TT
>
    </PRE
><P
>This generates a 1024-bit RSA key pair, unencrypted, into
    <TT
CLASS="FILENAME"
>privkey.pem</TT
>; it also generates a self-signed X.509
    certificate for the public key into <TT
CLASS="FILENAME"
>signer.pem</TT
>. The
    certificate is valid for 365 days, i.e., a year.
    </P
><P
>Let's rename <TT
CLASS="FILENAME"
>privkey.pem</TT
> so that we know it is
    a companion of <TT
CLASS="FILENAME"
>signer.pem</TT
>'s:
    </P
><PRE
CLASS="SCREEN"
>    <TT
CLASS="USERINPUT"
><B
>mv privkey.pem signer_key.pem</B
></TT
>
    </PRE
><P
>To verify the content of <TT
CLASS="FILENAME"
>signer.pem</TT
>, execute the
    following:
    </P
><PRE
CLASS="SCREEN"
>    <TT
CLASS="USERINPUT"
><B
>openssl x509 -noout -text -in signer.pem
    </B
></TT
>
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number: 0 (0x0)
            Signature Algorithm: md5WithRSAEncryption
            Issuer: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom
            Validity
                Not Before: Mar 24 12:56:16 2001 GMT
                Not After : Mar 24 12:56:16 2002 GMT
            Subject: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                RSA Public Key: (1024 bit)
                    Modulus (1024 bit):
                        00:a9:d6:e2:b5:11:3b:ae:3c:e2:17:31:70:e1:6e:
                        01:f4:19:6d:bd:2a:42:36:2b:37:34:e2:83:1d:0d:
                        11:2e:b4:99:44:db:10:67:be:97:5f:5b:1a:26:33:
                        46:23:2f:95:04:7a:35:da:9d:f9:26:88:39:9e:17:
                        cd:3e:eb:a8:19:8d:a8:2a:f1:43:da:55:a9:2e:2c:
                        65:ed:04:71:42:ce:73:53:b8:ea:7e:c7:f0:23:c6:
                        63:c5:5e:68:96:64:a7:b4:2a:94:26:76:eb:79:ea:
                        e3:4e:aa:82:09:4f:44:87:4a:12:62:b5:d7:1f:ca:
                        f2:ce:d5:ba:7e:1f:48:fd:b9
                    Exponent: 65537 (0x10001)
            X509v3 extensions:
                X509v3 Subject Key Identifier: 
                    29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99
                X509v3 Authority Key Identifier: 
                    keyid:29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99
                    DirName:/C=SG/O=M2Crypto/CN=S/MIME Sender/Email=sender@example.dom
                    serial:00
    
                X509v3 Basic Constraints: 
                    CA:TRUE
        Signature Algorithm: md5WithRSAEncryption
            68:c8:6b:1b:fa:7c:9a:39:35:76:18:15:c9:fd:89:97:62:db:
            7a:b0:2d:13:dd:97:e8:1b:7a:9f:22:27:83:24:9d:2e:56:ec:
            97:89:3c:ef:16:55:80:5a:18:7c:22:d0:f6:bb:e3:a4:e8:59:
            30:ff:99:5a:93:3e:ea:bc:ee:7f:8d:d6:7d:37:8c:ac:3d:74:
            80:ce:7a:99:ba:27:b9:2a:a3:71:fa:a5:25:ba:47:17:df:07:
            56:96:36:fd:60:b9:6c:96:06:e8:e3:7b:9f:4b:6a:95:71:a8:
            34:fc:fc:b5:88:8b:c4:3f:1e:24:f6:52:47:b2:7d:44:67:d9:
            83:e8
    </PRE
><P
>Next, we generate a self-signed X.509 certificate for the
    recipient. Note that <TT
CLASS="FILENAME"
>privkey.pem</TT
> will be
    recreated.
    </P
><PRE
CLASS="SCREEN"
>    <TT
CLASS="USERINPUT"
><B
>openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out recipient.pem
    </B
></TT
>
    Using configuration from /usr/local/pkg/openssl/openssl.cnf
    Generating a 1024 bit RSA private key
    .....................................++++++
    .................++++++
    writing new private key to 'privkey.pem'
    -----
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [AU]:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>SG</I
></TT
></B
></TT
>
    State or Province Name (full name) [Some-State]:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>.</I
></TT
></B
></TT
>
    Locality Name (eg, city) []:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>.</I
></TT
></B
></TT
>
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>M2Crypto</I
></TT
></B
></TT
>
    Organizational Unit Name (eg, section) []:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>.</I
></TT
></B
></TT
>
    Common Name (eg, YOUR name) []:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>S/MIME Recipient</I
></TT
></B
></TT
>
    Email Address []:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>recipient@example.dom</I
></TT
></B
></TT
>
    </PRE
><P
>Again, rename <TT
CLASS="FILENAME"
>privkey.pem</TT
>:
    </P
><PRE
CLASS="SCREEN"
>    <TT
CLASS="USERINPUT"
><B
>mv privkey.pem recipient_key.pem</B
></TT
>
    </PRE
><P
>In the examples to follow, S/MIME Sender,
    <TT
CLASS="EMAIL"
>&#60;<A
HREF="mailto:sender@example.dom"
>sender@example.dom</A
>&#62;</TT
>, shall be the sender of S/MIME messages,
    while S/MIME Recipient, <TT
CLASS="EMAIL"
>&#60;<A
HREF="mailto:recipient@example.dom"
>recipient@example.dom</A
>&#62;</TT
>, shall be the
    recipient of S/MIME messages.
    </P
><P
>Armed with the key pairs and certificates, we are now ready to begin 
    programming S/MIME in Python. 
    </P
><DIV
CLASS="NOTE"
><BLOCKQUOTE
CLASS="NOTE"
><P
><B
>Note: </B
>The private keys generated above are
    <I
CLASS="EMPHASIS"
>not passphrase-protected</I
>, i.e., they are
    <I
CLASS="EMPHASIS"
>in the clear</I
>. Anyone who has access to such a key can
    generate S/MIME-signed messages with it, and decrypt S/MIME messages
    encrypted to it's corresponding public key.
    </P
><P
>We may passphrase-protect the keys, if we so choose. M2Crypto will 
    prompt the user for the passphrase when such a key is being loaded.
    </P
></BLOCKQUOTE
></DIV
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="M2CRYPTO-SMIME"
>M2Crypto.SMIME</A
></H1
><P
>The Python programmer accesses M2Crypto's S/MIME functionality
    through class <TT
CLASS="CLASSNAME"
>SMIME</TT
> in the module
    <TT
CLASS="CLASSNAME"
>M2Crypto.SMIME</TT
>. Typically, an <TT
CLASS="CLASSNAME"
>SMIME</TT
> 
    object is instantiated; the object is then set up for the intended
    operation: sign, encrypt, decrypt or verify; finally, the operation is invoked on 
    the object.
    </P
><P
><TT
CLASS="CLASSNAME"
>M2Crypto.SMIME</TT
> makes extensive use of
    <TT
CLASS="CLASSNAME"
>M2Crypto.BIO</TT
>: <TT
CLASS="CLASSNAME"
>M2Crypto.BIO</TT
>
    is a Python abstraction of the <TT
CLASS="CLASSNAME"
>BIO</TT
> abstraction in
    OpenSSL. A commonly used <TT
CLASS="CLASSNAME"
>BIO</TT
> abstraction in M2Crypto is
    <TT
CLASS="CLASSNAME"
>M2Crypto.BIO.MemoryBuffer</TT
>, which implements a
    memory-based file-like object, similar to Python's own 
    <TT
CLASS="CLASSNAME"
>StringIO</TT
>.
    </P
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="SIGN"
>Sign</A
></H1
><P
>The following code demonstrates how to generate an S/MIME-signed
    message. <TT
CLASS="FILENAME"
>randpool.dat</TT
> contains random data which is
    used to seed OpenSSL's pseudo-random number generator via M2Crypto.
    </P
><PRE
CLASS="PROGRAMLISTING"
>    from M2Crypto import BIO, Rand, SMIME

    def makebuf(text):
        return BIO.MemoryBuffer(text)

    # Make a MemoryBuffer of the message.
    buf = makebuf('a sign of our times')

    # Seed the PRNG.
    Rand.load_file('randpool.dat', -1)

    # Instantiate an SMIME object; set it up; sign the buffer.
    s = SMIME.SMIME()
    s.load_key('signer_key.pem', 'signer.pem')
    p7 = s.sign(buf)
    </PRE
><P
><TT
CLASS="VARNAME"
>p7</TT
> now contains a <I
CLASS="EMPHASIS"
>PKCS #7 signature
    blob</I
> wrapped in an <TT
CLASS="CLASSNAME"
>M2Crypto.SMIME.PKCS7</TT
>
    object. Note that <TT
CLASS="VARNAME"
>buf</TT
> has been consumed by
    <TT
CLASS="FUNCTION"
>sign()</TT
> and has to be recreated if it is to be used
    again.
    </P
><P
>We may now send the signed message via SMTP. In these examples, we
    shall not do so; instead, we'll render the S/MIME output in
    mail-friendly format, and pretend that our messages are sent and 
    received correctly.
    </P
><PRE
CLASS="PROGRAMLISTING"
>    # Recreate buf.
    buf = makebuf('a sign of our times')

    # Output p7 in mail-friendly format.
    out = BIO.MemoryBuffer()
    out.write('From: sender@example.dom\n')
    out.write('To: recipient@example.dom\n')
    out.write('Subject: M2Crypto S/MIME testing\n')
    s.write(out, p7, buf)

    print out.read()

    # Save the PRNG's state.
    Rand.save_file('randpool.dat')
    </PRE
><P
>Here's the output:
    </P
><PRE
CLASS="SCREEN"
>    From: sender@example.dom
    To: recipient@example.dom
    Subject: M2Crypto S/MIME testing
    MIME-Version: 1.0
    Content-Type: multipart/signed ; protocol="application/x-pkcs7-signature" ; micalg=sha1 ; boundary="----3C93156FC7B4EBF49FE9C7DB7F503087"
    
    This is an S/MIME signed message
    
    ------3C93156FC7B4EBF49FE9C7DB7F503087
    a sign of our times
    ------3C93156FC7B4EBF49FE9C7DB7F503087
    Content-Type: application/x-pkcs7-signature; name="smime.p7s"
    Content-Transfer-Encoding: base64
    Content-Disposition: attachment; filename="smime.p7s"
    
    MIIE8AYJKoZIhvcNAQcCoIIE4TCCBN0CAQExCzAJBgUrDgMCGgUAMCIGCSqGSIb3
    DQEHAaAVBBNhIHNpZ24gb2Ygb3VyIHRpbWVzoIIC5zCCAuMwggJMoAMCAQICAQAw
    DQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv
    MRYwFAYDVQQDEw1TL01JTUUgU2VuZGVyMSEwHwYJKoZIhvcNAQkBFhJzZW5kZXJA
    ZXhhbXBsZS5kb20wHhcNMDEwMzMxMTE0MDMzWhcNMDIwMzMxMTE0MDMzWjBbMQsw
    CQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBT
    ZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbTCBnzANBgkq
    hkiG9w0BAQEFAAOBjQAwgYkCgYEA5c5Tj1CHTSOxa1q2q0FYiwMWYHptJpJcvtZm
    UwrgU5sHrA8OnCM0cDXEj0KPf3cfNjHffB8HWMzI4UEgNmFXQNsxoGZ+iqwxLlNj
    y9Mh7eFW/Bjq5hNXbouSlQ0rWBRkoxV64y+t6lQehb32WfYXQbKFxFJSXzSxOx3R
    8YhSPd0CAwEAAaOBtjCBszAdBgNVHQ4EFgQUXOyolL1t4jaBwZFRM7MS8nBLzUow
    gYMGA1UdIwR8MHqAFFzsqJS9beI2gcGRUTOzEvJwS81KoV+kXTBbMQswCQYDVQQG
    EwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIx
    ITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbYIBADAMBgNVHRMEBTAD
    AQH/MA0GCSqGSIb3DQEBBAUAA4GBAHo3DrCHR86fSTVAvfiXdSswWqKtCEhUHRdC
    TLFGl4hDk2GyZxaFuqZwiURz/H7nMicymI2wkz8H/wyHFg8G3BIehURpj2v/ZWXY
    eovbgS7EZALVVkDj4hNl/IIHWd6Gtv1UODf7URbxtl3hQ9/eTWITrefT1heuPnar
    8czydsOLMYIBujCCAbYCAQEwYDBbMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJD
    cnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNl
    bmRlckBleGFtcGxlLmRvbQIBADAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzEL
    BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAxMDMzMTExNDUwMlowIwYJKoZI
    hvcNAQkEMRYEFOoeRUd8ExIYXfQq8BTFuKWrSP3iMFIGCSqGSIb3DQEJDzFFMEMw
    CgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsO
    AwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIGAQpU8hFUtLCF6hO2t
    ec9EYJ/Imqqiiw+BxWxkUUVT81Vbjwdn9JST6+sztM5JRP2ZW+b4txEjZriYC8f3
    kv95YMTGbIsuWkJ93GrbvqoJ/CxO23r9WWRnZEm/1EZN9ZmlrYqzBTxnNRmP3Dhj
    cW8kzZwH+2/2zz2G7x1HxRWH95A=
    
    ------3C93156FC7B4EBF49FE9C7DB7F503087--
    </PRE
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="VERIFY"
>Verify</A
></H1
><P
>Assume the above output has been saved into <TT
CLASS="FILENAME"
>sign.p7</TT
>. 
    Let's now verify the signature:
    </P
><PRE
CLASS="PROGRAMLISTING"
>    from M2Crypto import SMIME, X509
    
    # Instantiate an SMIME object.
    s = SMIME.SMIME()
    
    # Load the signer's cert.
    x509 = X509.load_cert('signer.pem')
    sk = X509.X509_Stack()
    sk.push(x509)
    s.set_x509_stack(sk)
    
    # Load the signer's CA cert. In this case, because the signer's
    # cert is self-signed, it is the signer's cert itself.
    st = X509.X509_Store()
    st.load_info('signer.pem')
    s.set_x509_store(st)
    
    # Load the data, verify it.
    p7, data = SMIME.smime_load_pkcs7('sign.p7')
    v = s.verify(p7)
    print v
    print data
    print data.read()
    </PRE
><P
>Here's the output of the above program:
    </P
><PRE
CLASS="SCREEN"
>    a sign of our times
    &lt;M2Crypto.BIO.BIO instance at 0x822012c&gt;
    a sign of our times
    </PRE
><P
>Suppose, instead of loading <TT
CLASS="FILENAME"
>signer.pem</TT
> above,
    we load <TT
CLASS="FILENAME"
>recipient.pem</TT
>. That is, we do a global
    substitution of <TT
CLASS="LITERAL"
>recipient.pem</TT
> for
    <TT
CLASS="LITERAL"
>signer.pem</TT
> in the above program. Here's the modified 
    program's output:
    </P
><PRE
CLASS="SCREEN"
>    Traceback (most recent call last):
      File "./verify.py", line 22, in ?
        v = s.verify(p7)
      File "/usr/local/home/ngps/prog/m2/M2Crypto/SMIME.py", line 205, in verify
        raise SMIME_Error, Err.get_error()
    M2Crypto.SMIME.SMIME_Error: 312:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:pk7_smime.c:213:Verify error:self signed certificate
    </PRE
><P
>As displayed, the error is generated by line 213 of OpenSSL's
    <TT
CLASS="FILENAME"
>pk7_smime.c</TT
> (as of OpenSSL 0.9.6); if you are a 
    C programmer, you may wish to look up the C source to explore OpenSSL's 
    S/MIME implementation and understand why the error message is worded thus.
    </P
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="ENCRYPT"
>Encrypt</A
></H1
><P
>We now demonstrate how to generate an S/MIME-encrypted message:
    </P
><PRE
CLASS="PROGRAMLISTING"
>    from M2Crypto import BIO, Rand, SMIME, X509
    
    def makebuf(text):
        return BIO.MemoryBuffer(text)
    
    # Make a MemoryBuffer of the message.
    buf = makebuf('a sign of our times')
    
    # Seed the PRNG.
    Rand.load_file('randpool.dat', -1)

    # Instantiate an SMIME object.
    s = SMIME.SMIME()
    
    # Load target cert to encrypt to.
    x509 = X509.load_cert('recipient.pem')
    sk = X509.X509_Stack()
    sk.push(x509)
    s.set_x509_stack(sk)
    
    # Set cipher: 3-key triple-DES in CBC mode.
    s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
    
    # Encrypt the buffer.
    p7 = s.encrypt(buf)
        
    # Output p7 in mail-friendly format.
    out = BIO.MemoryBuffer()
    out.write('From: sender@example.dom\n')
    out.write('To: recipient@example.dom\n')
    out.write('Subject: M2Crypto S/MIME testing\n')
    s.write(out, p7)
    
    print out.read()

    # Save the PRNG's state.
    Rand.save_file('randpool.dat')
    </PRE
><P
>Here's the output of the above program:
    </P
><PRE
CLASS="SCREEN"
>    From: sender@example.dom
    To: recipient@example.dom
    Subject: M2Crypto S/MIME testing
    MIME-Version: 1.0
    Content-Disposition: attachment; filename="smime.p7m"
    Content-Type: application/x-pkcs7-mime; name="smime.p7m"
    Content-Transfer-Encoding: base64
    
    MIIBVwYJKoZIhvcNAQcDoIIBSDCCAUQCAQAxggEAMIH9AgEAMGYwYTELMAkGA1UE
    BhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBp
    ZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5kb20CAQAwDQYJ
    KoZIhvcNAQEBBQAEgYCBaXZ+qjpBEZwdP7gjfzfAtQitESyMwo3i+LBOw6sSDir6
    FlNDPCnkrTvqDX3Rt6X6vBtTCYOm+qiN7ujPkOU61cN7h8dvHR8YW9+0IPY80/W0
    lZ/HihSRgwTNd7LnxUUcPx8YV1id0dlmP0Hz+Lg+mHf6rqaR//JcYhX9vW4XvjA7
    BgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcECMN+qya6ADywgBgHr9Jkhwn5Gsdu7BwX
    nIQfYTYcdL9I5Sk=
    </PRE
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="DECRYPT"
>Decrypt</A
></H1
><P
>Assume the above output has been saved into <TT
CLASS="FILENAME"
>encrypt.p7</TT
>. 
    Decrypt the message thusly:
    </P
><PRE
CLASS="PROGRAMLISTING"
>    from M2Crypto import BIO, SMIME, X509
    
    # Instantiate an SMIME object.
    s = SMIME.SMIME()
    
    # Load private key and cert.
    s.load_key('recipient_key.pem', 'recipient.pem')
    
    # Load the encrypted data.
    p7, data = SMIME.smime_load_pkcs7('encrypt.p7')
    
    # Decrypt p7.
    out = s.decrypt(p7)
        
    print out
    </PRE
><P
>Here's the output:
    </P
><PRE
CLASS="SCREEN"
>    a sign of our times
    </PRE
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="SIGN-AND-ENCRYPT"
>Sign and Encrypt</A
></H1
><P
>Here's how to generate an S/MIME-signed/encrypted message:
    </P
><PRE
CLASS="PROGRAMLISTING"
>    from M2Crypto import BIO, Rand, SMIME, X509
    
    def makebuf(text):
        return BIO.MemoryBuffer(text)
    
    # Make a MemoryBuffer of the message.
    buf = makebuf('a sign of our times')
    
    # Seed the PRNG.
    Rand.load_file('randpool.dat', -1)
    
    # Instantiate an SMIME object.
    s = SMIME.SMIME()
    
    # Load signer's key and cert. Sign the buffer.
    s.load_key('signer_key.pem', 'signer.pem')
    p7 = s.sign(buf)
    
    # Load target cert to encrypt the signed message to.
    x509 = X509.load_cert('recipient.pem')
    sk = X509.X509_Stack()
    sk.push(x509)
    s.set_x509_stack(sk)
    
    # Set cipher: 3-key triple-DES in CBC mode.
    s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
    
    # Create a temporary buffer.
    tmp = BIO.MemoryBuffer()
    
    # Write the signed message into the temporary buffer.
    s.write(tmp, p7, buf)
    
    # Encrypt the temporary buffer.
    p7 = s.encrypt(tmp)
        
    # Output p7 in mail-friendly format.
    out = BIO.MemoryBuffer()
    out.write('From: sender@example.dom\n')
    out.write('To: recipient@example.dom\n')
    out.write('Subject: M2Crypto S/MIME testing\n')
    s.write(out, p7)
    
    print out.read()
    
    # Save the PRNG's state.
    Rand.save_file('randpool.dat')
    </PRE
><P
>Here's the output of the above program:
    </P
><PRE
CLASS="SCREEN"
>    From: sender@example.dom
    To: recipient@example.dom
    Subject: M2Crypto S/MIME testing
    MIME-Version: 1.0
    Content-Disposition: attachment; filename="smime.p7m"
    Content-Type: application/x-pkcs7-mime; name="smime.p7m"
    Content-Transfer-Encoding: base64
    
    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
    </PRE
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="DECRYPT-AND-VERIFY"
>Decrypt and Verify</A
></H1
><P
>Suppose the above output has been saved into
    <TT
CLASS="FILENAME"
>se.p7</TT
>. The following demonstrates how to decrypt and
    verify it:
    </P
><PRE
CLASS="PROGRAMLISTING"
>    from M2Crypto import BIO, SMIME, X509
    
    # Instantiate an SMIME object.
    s = SMIME.SMIME()
    
    # Load private key and cert.
    s.load_key('recipient_key.pem', 'recipient.pem')
    
    # Load the signed/encrypted data.
    p7, data = SMIME.smime_load_pkcs7('se.p7')
    
    # After the above step, 'data' == None.  
    # Decrypt p7. 'out' now contains a PKCS #7 signed blob.
    out = s.decrypt(p7)
    
    # Load the signer's cert.
    x509 = X509.load_cert('signer.pem')
    sk = X509.X509_Stack()
    sk.push(x509)
    s.set_x509_stack(sk)
    
    # Load the signer's CA cert. In this case, because the signer's
    # cert is self-signed, it is the signer's cert itself.
    st = X509.X509_Store()
    st.load_info('signer.pem')
    s.set_x509_store(st)
    
    # Recall 'out' contains a PKCS #7 blob.
    # Transform 'out'; verify the resulting PKCS #7 blob.
    p7_bio = BIO.MemoryBuffer(out)
    p7, data = SMIME.smime_load_pkcs7_bio(p7_bio)
    v = s.verify(p7)
    
    print v
    </PRE
><P
>The output is as follows:
    </P
><PRE
CLASS="SCREEN"
>    a sign of our times
    </PRE
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="SMTP"
>Sending S/MIME messages via SMTP</A
></H1
><P
>In the above examples, we've assumed that our S/MIME messages 
    are sent and received automagically. The following is a Python function that 
    generates S/MIME-signed/encrypted messages and sends them via SMTP:
    </P
><PRE
CLASS="PROGRAMLISTING"
>    from M2Crypto import BIO, SMIME, X509
    import smtplib, string, sys
    
    def sendsmime(from_addr, to_addrs, subject, msg, from_key, from_cert=None, to_certs=None, smtpd='localhost'):
    
        msg_bio = BIO.MemoryBuffer(msg)
        sign = from_key
        encrypt = to_certs
    
        s = SMIME.SMIME()
        if sign:
            s.load_key(from_key, from_cert)
            p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT)
            msg_bio = BIO.MemoryBuffer(msg) # Recreate coz sign() has consumed it.
    
        if encrypt:
            sk = X509.X509_Stack()
            for x in to_certs:
                sk.push(X509.load_cert(x))
            s.set_x509_stack(sk)
            s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
            tmp_bio = BIO.MemoryBuffer()
            if sign:
                s.write(tmp_bio, p7)
            else:
                tmp_bio.write(msg)
            p7 = s.encrypt(tmp_bio)
    
        out = BIO.MemoryBuffer()
        out.write('From: %s\r\n' % from_addr)
        out.write('To: %s\r\n' % string.join(to_addrs, ", "))
        out.write('Subject: %s\r\n' % subject) 
        if encrypt:
            s.write(out, p7)
        else:
            if sign:
                s.write(out, p7, msg_bio, SMIME.PKCS7_TEXT)
            else:
                out.write('\r\n')
                out.write(msg)
        out.close()
    
        smtp = smtplib.SMTP()
        smtp.connect(smtpd)
        smtp.sendmail(from_addr, to_addrs, out.read())
        smtp.quit()
    </PRE
><P
>This function sends plain, S/MIME-signed, S/MIME-encrypted,
    and S/MIME-signed/encrypted messages, depending on the parameters
    <TT
CLASS="PARAMETER"
><I
>from_key</I
></TT
> and <TT
CLASS="PARAMETER"
><I
>to_certs</I
></TT
>. The
    function's output interoperates with Netscape Messenger.
    </P
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="VERIFYING-ORIGIN"
>Verifying origin of S/MIME messages</A
></H1
><P
>In our examples above that decrypt or verify messages, we skipped
    a step: verifying that the <TT
CLASS="LITERAL"
>from</TT
> address of the message 
    matches the <TT
CLASS="LITERAL"
>email address</TT
> attribute in the sender's 
    certificate.
    </P
><P
>The premise of current X.509 certification practice is that the
    CA is supposed to verify your identity, and to issue a certificate with 
    <TT
CLASS="LITERAL"
>email address</TT
> that matches your actual mail address. 
    (Verisign's March 2001 failure in identity verification resulting in
    Microsoft certificates being issued to spoofers notwithstanding.)
    </P
><P
>If you run your own CA, your certification practice is up to you, of
    course, and it would probably be part of your security policy.
    </P
><P
>Whether your S/MIME messaging application needs to verify the 
    <TT
CLASS="LITERAL"
>from</TT
> addresses of S/MIME messages depends on your
    security policy and your system's threat model, as always.
    </P
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="NETSCAPE-MESSENGER"
>Interoperating with Netscape Messenger</A
></H1
><P
>Suppose S/MIME Recipient uses Netscape Messenger. To enable Messenger 
    to handle S/MIME messages from S/MIME Sender, S/MIME Recipient needs 
    to configure Messenger with his private key and certificate, as well as S/MIME
    Sender's certificate.
    </P
><DIV
CLASS="NOTE"
><BLOCKQUOTE
CLASS="NOTE"
><P
><B
>Note: </B
>Configuring Messenger's POP or IMAP settings so that it retrieves
    mail correctly is beyond the scope of this HOWTO.  
    </P
></BLOCKQUOTE
></DIV
><P
>The following steps demonstrate how to import S/MIME Recipient's
    private key and certificate for Messenger:
    </P
><DIV
CLASS="PROCEDURE"
><OL
TYPE="1"
><LI
><P
>Transform S/MIME Recipient's private key and certificate into
    <I
CLASS="EMPHASIS"
>PKCS #12</I
> format.
    </P
><PRE
CLASS="SCREEN"
>    <TT
CLASS="USERINPUT"
><B
>openssl pkcs12 -export -in recipient.pem -inkey recipient_key.pem -name "S/MIME Recipient" -out recipient.p12
    </B
></TT
>
    Enter Export Password:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>&lt;enter&gt;</I
></TT
></B
></TT
>
    Verifying password - Enter Export Password:<TT
CLASS="USERINPUT"
><B
><TT
CLASS="REPLACEABLE"
><I
>&lt;enter&gt;</I
></TT
></B
></TT
>
    </PRE
></LI
><LI
><P
>Start Messenger.
    </P
></LI
><LI
><P
>Click on the (open) "lock" icon at the bottom left corner of
    Messenger's window. This brings up the "Security Info" dialog box.
    </P
></LI
><LI
><P
>Click on "Yours" under "Certificates".
    </P
></LI
><LI
><P
>Select "Import a certificate", then pick
    <TT
CLASS="FILENAME"
>recipient.p12</TT
> from the ensuing file selection dialog
    box.
    </P
></LI
></OL
></DIV
><P
>Next, you need to import <TT
CLASS="FILENAME"
>signer.pem</TT
> as a CA
    certificate, so that Messenger will mark messages signed by S/MIME Sender as
    "trusted":
    </P
><DIV
CLASS="PROCEDURE"
><OL
TYPE="1"
><LI
><P
>Create a DER encoding of <TT
CLASS="FILENAME"
>signer.pem</TT
>.
    </P
><PRE
CLASS="SCREEN"
>    <TT
CLASS="USERINPUT"
><B
>openssl x509 -inform pem -outform der -in signer.pem -out signer.der
    </B
></TT
>
    </PRE
></LI
><LI
><P
>Install <TT
CLASS="FILENAME"
>signer.der</TT
> into Messenger as MIME type
    <TT
CLASS="LITERAL"
>application/x-x509-ca-cert</TT
>. You do this by downloading
    <TT
CLASS="FILENAME"
>signer.der</TT
> via Navigator from a HTTP or HTTPS server,
    with the correct MIME type mapping. (You may use 
    <TT
CLASS="FILENAME"
>demo/ssl/https_srv.py</TT
>, bundled with M2Crypto, for
    this purpose.) Follow the series of dialog boxes to accept
    <TT
CLASS="FILENAME"
>signer.der</TT
> as a CA for certifying email users.
    </P
></LI
></OL
></DIV
><P
>S/MIME Recipient is now able to decrypt and read S/MIME Sender's
    messages with Messenger. Messenger will indicate that S/MIME Sender's
    messages are signed, encrypted, or encrypted <I
CLASS="EMPHASIS"
>and</I
>
    signed, as the case may be, via the "stamp" icon on the message window's
    top right corner.
    </P
><P
>Clicking on the "stamp" icon brings you to the Security Info dialog
    box. Messenger informs you that the message is, say, encrypted with
    168-bit DES-EDE3-CBC and that it is digitally signed by the private key
    corresponding to the public key contained in the certificate
    <TT
CLASS="FILENAME"
>signer.pem</TT
>.
    </P
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="MICROSOFT-OUTLOOK"
>Interoperating with Microsoft Outlook</A
></H1
><P
>I do not know how to do this, as I do not use Outlook. (Nor do I use
    Netscape Messenger, actually. I use Mutt, top dog of MUAs. ;-) Information on 
    how to configure Outlook with keys and certificates so that it handles 
    S/MIME mail is gratefully accepted.
    </P
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="ZSMIME"
>ZSmime</A
></H1
><P
>ZSmime is a <A
HREF="http://www.zope.org"
TARGET="_top"
>Zope</A
>
    <I
CLASS="EMPHASIS"
>product</I
> that enables Zope to generate 
    S/MIME-signed/encrypted messages. ZSmime demonstrates how to invoke 
    M2Crypto in a web application server extension.
    </P
><P
>ZSmime has its own <A
HREF="http://sandbox.rulemaker.net/ngps/zope/zsmime/howto.html"
TARGET="_top"
>HOWTO</A
>
    explaining its usage. (That HOWTO has some overlap in content with
    this document.)
    </P
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="RESOURCES"
>Resources</A
></H1
><P
></P
><UL
><LI
STYLE="list-style-type: opencircle"
><P
>IETF S/MIME Working Group - 
    <A
HREF="http://www.imc.org/ietf-smime"
TARGET="_top"
>    http://www.imc.org/ietf-smime</A
>
    </P
></LI
><LI
STYLE="list-style-type: opencircle"
><P
>S/MIME and OpenPGP - 
    <A
HREF="http://www.imc.org/smime-pgpmime.html"
TARGET="_top"
>    http://www.imc.org/smime-pgpmime.html</A
>
    </P
></LI
><LI
STYLE="list-style-type: opencircle"
><P
>S/MIME Freeware Library - 
    <A
HREF="http://www.getronicsgov.com/hot/sfl_home.htm"
TARGET="_top"
>    http://www.getronicsgov.com/hot/sfl_home.htm</A
>
    </P
></LI
><LI
STYLE="list-style-type: opencircle"
><P
>Mozilla Network Security Services -
    <A
HREF="http://www.mozilla.org/projects/security/pkg/nss"
TARGET="_top"
>    http://www.mozilla.org/projects/security/pkg/nss</A
>
    </P
></LI
><LI
STYLE="list-style-type: opencircle"
><P
>S/MIME Cracking Screen Saver -
    <A
HREF="http://www.counterpane.com/smime.html"
TARGET="_top"
>    http://www.counterpane.com/smime.html</A
>
    </P
></LI
></UL
></DIV
><DIV
CLASS="SECT1"
><HR><H1
CLASS="SECT1"
><A
NAME="ID-KLUDGE"
></A
></H1
><P
>    <TT
CLASS="LITERAL"
>$Id:howto.smime.html 583 2007-10-01 19:23:12Z heikki $</TT
>
    </P
></DIV
></DIV
></BODY
></HTML
>